package qu.sol2bpel.services;

import java.io.File;
import java.io.StringReader;
import java.nio.file.FileSystem;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Part;
import javax.wsdl.PortType;
import javax.wsdl.extensions.schema.Schema;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.io.FileUtils;
import org.jdom.Element;
import org.jdom.input.DOMBuilder;
import org.jdom.output.XMLOutputter;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import qu.sol2bpel.workflow.Config;

import com.ibm.wsdl.PortImpl;
import com.ibm.wsdl.ServiceImpl;
import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;

public class ServicesLocalRegistry {

	static ArrayList<Service_WSDL> services_list;
	static ArrayList<Service_bQoS> services_QoS;

	public ServicesLocalRegistry()
	{
		services_list = new ArrayList<Service_WSDL>();
		services_QoS = new ArrayList<Service_bQoS>();
	}

	public ServicesLocalRegistry(String directory)
	{
		services_list = new ArrayList<Service_WSDL>();
		services_QoS = new ArrayList<Service_bQoS>();
		loadRegistry(directory);
	}
	public void loadRegistry(String directoryPath){


		String file;
		File folder = new File(directoryPath);
		File[] listOfFiles = folder.listFiles(); 

		for (int i = 0; i < listOfFiles.length; i++) 
		{
			if (listOfFiles[i].isFile()) 
			{
				file = listOfFiles[i].getName();
				if (file.endsWith(".wsdl") || file.endsWith(".WSDL"))
				{
					addService(directoryPath+"\\"+file);
				}
			}
		}
	}

	public void addService(String wsdlFilePath)
	{
		Service_WSDL wsdl = new Service_WSDL(wsdlFilePath);
		services_list.add(wsdl);
	}

	public void addService(Service_WSDL wsdl, Service_bQoS bQoS)
	{
		services_list.add(wsdl);
		services_QoS.add(bQoS);
	}

	static public String getServiceUrl(int service_indx, String operation)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			String nameSpace = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getTargetNamespace(); 
			QName key =  ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getQName();
			String portKey = "MatServices";
			return ((SOAPAddressImpl)((PortImpl)((ServiceImpl)((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getAllServices().get(key)).getPort(portKey)).getExtensibilityElements().get(0)).getLocationURI();
		}
		return "NOT_FOUND";
	}

	static public String getServiceName(int service_indx)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			String nameSpace = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getTargetNamespace(); 
			QName key =  ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getQName();

			String ServiceQname= ((ServiceImpl)((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getAllServices().get(key)).getQName().toString();

			StringTokenizer tokenizer = new StringTokenizer(ServiceQname, "}");
			tokenizer.nextToken(); String ServiceName = tokenizer.nextToken();
			return ServiceName;
		}
		return "NOT_FOUND";
	}

	static public String getServicePortName(int service_indx)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			String nameSpace = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getTargetNamespace(); 
			QName key =  ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getQName();

			Iterator I= ((ServiceImpl)((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getAllServices().get(key)).getPorts().values().iterator();
			String portName ="";
			while(I.hasNext())
			{
				PortImpl p = (PortImpl)I.next();
				portName = p.getName();			
			}			
			return portName;
		}
		return "NOT_FOUND";
	}
	static public String getServiceTargetNamespace(int service_indx)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			String nameSpace = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getTargetNamespace(); 
			return nameSpace;
		}
		return null;
	}

	static public String getServicePortType(int service_indx, String operation)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			Iterator IP = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getPortTypes().values().iterator();
			while(IP.hasNext())
			{
				PortType p = (PortType)IP.next();
				//System.out.println("PortType :::::: "+p.getQName().getLocalPart());
				Iterator LI = p.getOperations().iterator();
				while (LI.hasNext())
				{
					//System.out.println("Operation  \\\\\\ "+ ((Operation)LI.next()).getName());//getQName().getLocalPart());
					String Op = ((Operation)LI.next()).getName();
					if(Op.contains(operation))
						return p.getQName().getLocalPart();
				}

			}
		}
		return null;
	}

	static public String getServiceOperationName(int service_indx, String operation)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			Iterator IP =((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getPortTypes().values().iterator();
			while(IP.hasNext())
			{
				PortType p = (PortType)IP.next();
				//	System.out.println("PortType :::::: "+p.getQName().getLocalPart());
				Iterator LI = p.getOperations().iterator();
				while (LI.hasNext())
				{
					//System.out.println("Operation  \\\\\\ "+ ((Operation)LI.next()).getName());//getQName().getLocalPart());
					String Op = ((Operation)LI.next()).getName();
					if(Op.contains(operation))
						return Op;
				}

			}
		}
		return null;
	}

	static public String getServiceOperationMessageName(int service_indx, String operation)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			Iterator IM = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getMessages().values().iterator();//entrySet().iterator();
			while (IM.hasNext())
			{
				String messageName= ((Message)IM.next()).getQName().getLocalPart();
				if(messageName.toLowerCase().contains(operation.toLowerCase()))
					return messageName;
			}
		}
		return null;
	}

	static public String getServiceOperationElementName(int service_indx, String operation)
	{
		if(service_indx>=0 && service_indx < services_list.size())
		{
			Iterator I = ((Service_WSDL)services_list.get(service_indx)).getWsdl_def().getMessages().values().iterator();//entrySet().iterator();
			while (I.hasNext())
			{
				Iterator I2 = ((Message)I.next()).getParts().values().iterator();
				while (I2.hasNext())
				{
					//System.out.println("Message Part ///  " +((Part)I2.next()).getElementName().getLocalPart().toString());//getQName().getLocalPart());
					String partName = ((Part)I2.next()).getElementName().getLocalPart().toString();
					if(partName.toLowerCase().contains(operation.toLowerCase()))
						return partName;
				}
			}
		}
		return null;
	}

	static public ArrayList<String> getServiceElementSchema(int chosen, String operation)
	{
		ArrayList<String> message_elements= new ArrayList<String>();

		String complextypeElementName= getServiceOperationElementName(chosen, operation);

		Schema schema = null ;
		if(((Service_WSDL)services_list.get(chosen)).getWsdl_def().getTypes() !=null &&  ((Service_WSDL)services_list.get(chosen)).getWsdl_def().getTypes().getExtensibilityElements() !=null){
			for (Object e : ((Service_WSDL)services_list.get(chosen)).getWsdl_def().getTypes().getExtensibilityElements()) {
				schema = (Schema)e;
			}
		}

		if (schema != null) {
			DOMBuilder domBuilder = new DOMBuilder();
			Element jdomSchemaElement = domBuilder.build(schema.getElement());
			XMLOutputter outputter = new XMLOutputter();
			String xmlout = outputter.outputString(jdomSchemaElement.getDocument());

			System.out.println(xmlout);
			StringReader in2 = new StringReader(xmlout);
			InputSource schemaSource = new InputSource(in2);

			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
			DocumentBuilder builder;  
			try 
			{  
				builder = factory.newDocumentBuilder();  
				org.w3c.dom.Document doc = builder.parse( new InputSource( new StringReader( xmlout ) ) ); 

				//get the root elememt
				org.w3c.dom.Element docEle = doc.getDocumentElement();

				boolean addchildrenElements = false;
				NodeList nl = docEle.getElementsByTagName("element");
				if(nl != null && nl.getLength() > 0) {
					for(int i = 0 ; i < nl.getLength();i++) {

						if((((org.w3c.dom.Element)nl.item(i)).getAttribute("name")).equals(complextypeElementName))
							addchildrenElements = true;
						else if((((org.w3c.dom.Element)nl.item(i)).getAttribute("name")).toLowerCase().contains("element"))
							addchildrenElements = false;
						else if(addchildrenElements)
						{
							org.w3c.dom.Element el = (org.w3c.dom.Element)nl.item(i);
							message_elements.add(el.getAttribute("name"));
							System.out.println(el.getAttribute("name"));
						}

					}
				}
				return message_elements;
			} catch (Exception e) {  
				e.printStackTrace();  
			} 
		}
		return null;
	}
	static public Service_WSDL getService(int indx)
	{
		if(indx>=0 && indx < services_list.size())
		{
			return (Service_WSDL)services_list.get(indx); 

		}
		return null;
	}
	static public int getServiceIndex(String IP, String operation)
	{
		int i = 0;
		QName portName=null;
		for(i=0; i< services_list.size(); i++)
		{
			//String nameSpace = ((Service_WSDL)services_list.get(i)).getWsdl_def().getTargetNamespace(); 

			String service =((Service_WSDL)services_list.get(i)).getWsdl_def().toString();
			if(service.contains(IP))
				return i;
		}

		return -1;
	}

	static public int sizeOfServicesList()
	{
		return services_list.size();
	}

	public static void main(String[] args)
	{
		ServicesLocalRegistry registry = new ServicesLocalRegistry();
		QoSParameters p_s1 = new QoSParameters(0.01, 0.1, 0.99, 0.90);
		QoSParameters p_s2 = new QoSParameters(0.01, 0.1, 0.99, 0.90);
		QoSParameters p_s3 = new QoSParameters(0.01, 0.1, 0.99, 0.90);
		QoSParameters p_s4 = new QoSParameters(0.01, 0.1, 0.99, 0.90);

		Service_bQoS qoS1 = new Service_bQoS(); qoS1.setQos(p_s1); 
		Service_WSDL wsdl1 = new Service_WSDL(Config.SERVICES_DIRECTORY+"\\multiply.wsdl"); registry.addService(wsdl1, qoS1); 
		Service_bQoS qoS2 = new Service_bQoS(); qoS2.setQos(p_s2); 
		Service_WSDL wsdl2 = new Service_WSDL(Config.SERVICES_DIRECTORY+"\\add.wsdl"); registry.addService(wsdl2, qoS2); 
		Service_bQoS qoS3 = new Service_bQoS(); qoS3.setQos(p_s3); 
		Service_WSDL wsdl3 = new Service_WSDL(Config.SERVICES_DIRECTORY+"\\put.wsdl"); registry.addService(wsdl3, qoS3); 
		Service_bQoS qoS4 = new Service_bQoS(); qoS4.setQos(p_s4); 
		Service_WSDL wsdl4 = new Service_WSDL(Config.SERVICES_DIRECTORY+"\\split.wsdl"); registry.addService(wsdl4, qoS4);

		System.out.println("SERVICE NAME: "+ServicesLocalRegistry.getServiceName(2));
		System.out.println("PORT NAME: "+ServicesLocalRegistry.getServicePortName(2));
		System.out.println("OPERATION ELEMENT NAME: "+ServicesLocalRegistry.getServiceOperationElementName(2, "multiply"));
	}
}
